package com.gzsxy.esjy.service.statistical.filter;

import com.gzsxy.esjy.redis.common.ThreadLocalProxyHolder;
import com.gzsxy.esjy.redis.extend.RedisService;
import com.gzsxy.esjy.redis.user.AuthContants;
import com.gzsxy.esjy.redis.user.ISystemUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 拦截器（把网关获取的登录用户通过代理方式存入ThreadLocal线程对象中）
 * @date 2022/1/19 16:58
 */
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {

    private long start = 0;

    /**
     * preHandle请求执行前执行的
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        start = System.currentTimeMillis();
        String accessToken = getToken(request);
        RedisService redisService = getBean(RedisService.class, request);
        DefaultUser loginUser = redisService.getValue(accessToken + "_token", DefaultUser.class);
        if (null == loginUser){
            loginUser = new DefaultUser();
        }
        ThreadLocalProxyHolder.set(loginUser);
        return true;
    }


    /**
     * postHandle是在请求结束之后，视图渲染之前执行的，但只有preHandle方法返回true的时候才会执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       log.info("{},cost={}ms",request.getRequestURI(),(System.currentTimeMillis() -start ));
    }


    /**
     * afterCompletion是视图渲染之后执行的，但只有postHandle方法返回true的时候才会执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //该方法通常用于清理资源等工作
        ThreadLocalProxyHolder.remove(ISystemUser.class);
    }



    /**
     * @description: 获取token
     * @param
     * @return
     */
    private String getToken(HttpServletRequest request){
        //从请求参数中获取access_token值
        String token = request.getParameter(AuthContants.TOKEN);
        //为空
        if (!StringUtils.hasText(token)){
            //从请求头拿Authorization
            token = request.getHeader(AuthContants.TOKEN_HEADER);
            //为空
            if (!StringUtils.hasText(token)){
                //从请求头拿access_token
                token = request.getHeader(AuthContants.TOKEN);
            }
            //不为空
            if (StringUtils.hasText(token)){
                //分割 如果是通过Authorization拿到的token是Bearer 544f80ad-bef7-4750-a1f5-a055a4306ea0
                String[] s = token.split(" ");
                if (s.length >1){
                    token = s[1];
                }
            }
        }
        return token;
    }


    public <T> T getBean(Class<T> clazz,HttpServletRequest request){
        //通过该方法获得的applicationContext 已经是初始化之后的applicationContext容器
        WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        return applicationContext.getBean(clazz);
    }
}
